package com.st.config;

import com.st.common.security.MyAuthenticationProvider;
import com.st.common.security.SwordUserDetails;
import com.st.common.security.SwordUserDetailsService;
import com.st.handler.*;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * @author shent
 * 认证相关配置
 */
@Primary
@Order(90)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    private static final String LOGIN_ENDPOINT = "/auth/login";
    private static final String LOGOUT_ENDPOINT = "/auth/logout";

    private static final String[] NO_AUTHORIZE_REQUESTS = {
            LOGIN_ENDPOINT,
            "/swagger-resources/configuration/ui",
            "/swagger-resources",
            "/swagger-resources/configuration/security",
            "/swagger-ui.html", "/error","/user/add"
    };

    @Override
    @SneakyThrows
    protected void configure(HttpSecurity http) {
        http
                .authorizeRequests()
                .antMatchers(NO_AUTHORIZE_REQUESTS).permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl(LOGIN_ENDPOINT)
                .successHandler(getBean(MyAuthenticationSuccessHandler.class))
                .failureHandler(getBean(MyAuthenticationFailureHandler.class))
                .and()
                .logout()
                .logoutUrl(LOGOUT_ENDPOINT)
                .clearAuthentication(true)
                .invalidateHttpSession(true)
                .logoutSuccessHandler(getBean(MyLogoutSuccessHandler.class))
                .and()
                // SessionRepository 持久化
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .maximumSessions(1)
                .sessionRegistry(getBean(SessionRegistry.class))
                .maxSessionsPreventsLogin(false);
        //todo remmber me
        http.csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(getBean(MyAuthenticationProvider.class));
        //todo remmber me
    }

    /**
     * 自定义sessionRegistry
     * 这里是为了用来获取全部session 然后使得权限变化的用户session失效
     */
    @Bean
    public SessionRegistry getSessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    @Override
    @SneakyThrows
    public AuthenticationManager authenticationManagerBean() {
        return super.authenticationManagerBean();
    }

    @Bean
    public BCryptPasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    protected <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
}
